using System;
using System.IO;
using System.Xml.Serialization;
using Mbs.Collections;
using Mbs.ComponentModel.Container.Activation;
using Mbs.ComponentModel.Container.Injection;
using Mbs.ComponentModel.Container.Lifestyle;
using Mbs.ComponentModel.Container.Listner;
using Mbs.ComponentModel.Container.Metadata;
using Mbs.Reflection;

namespace Mbs.ComponentModel.Container.Loader
{
    [Serializable]
    public class XmlLoader : LoaderAdapter
    {
        configuration cfg;
        IClassLoader ClassLoader;

        public XmlLoader(string xmlConfigFile)
        {
            cfg = Init(xmlConfigFile);
        }
       
        private static configuration Init(string xmlConfigFile)
        {

            if (File.Exists(xmlConfigFile))
            {
                XmlSerializer ser = null;
                try
                {
                    ser = new XmlSerializer(typeof(configuration));
                }
                catch (Exception ex)
                {
                    throw ex;
                }

                configuration result = null;

                try
                {
                    using(var stream = File.OpenRead(xmlConfigFile))
                        result = ser.Deserialize(stream) as configuration;
                }
                catch (Exception ex)
                {
                    throw ex;
                }

                return result;
            }
            return null;
        }

        public override void Load()
        {
            ClassLoader = Kernel.Get<IClassLoader>();

            if (cfg.components != null && cfg.components.Length > 0)
                cfg.components.Foreach(component => RegisterComponent(component));

            if (cfg.listners != null && cfg.listners.Length > 0)
                cfg.listners.Foreach(listner => RegisterListner(listner));

            if (cfg.lifestyles != null && cfg.lifestyles.Length > 0)
                cfg.lifestyles.Foreach(lifestyle => RegisterLifestyle(lifestyle));

            if (cfg.activators != null && cfg.activators.Length > 0)
                cfg.activators.Foreach(activator => RegisterActivator(activator));

            if (cfg.injectors != null && cfg.injectors.Length > 0)
                cfg.injectors.Foreach(injector => RegisterInjector(injector));
        }

        private void RegisterInjector(settingItem injector)
        {
            var injectorStragetyType = ClassLoader.LoadType(injector.value);
            Kernel.InjectStrategyManager.Register(Activator.CreateInstance(injectorStragetyType) as IInjectStrategy);
        }

        private void RegisterActivator(settingItem activator)
        {
            var activatorType = ClassLoader.LoadType(activator.value);
            Kernel.ActivatorFactory.Register(activator.name, ()=> Activator.CreateInstance(activatorType) as IActivator);
        }

        private void RegisterLifestyle(settingItem lifestyle)
        {
            var lifestyleType = ClassLoader.LoadType(lifestyle.value);
            Kernel.LifestyleManagerFactory.Register(lifestyle.name, () => Activator.CreateInstance(lifestyleType) as ILifestyleManager);
        }

        private void RegisterListner(settingItem listner)
        {
            var listnerType = ClassLoader.LoadType(listner.value);
            Kernel.ListnerManager.Register(Activator.CreateInstance(listnerType) as IKernelListner);
        }

        private void RegisterComponent(component component)
        {
            var service = ClassLoader.LoadType(component.service);
            var imp = ClassLoader.LoadType(component.type);

            var info = new ComponentInfo(component.id,service, imp, component.activator, component.lifestyleType, component.isLazyInit);
            if (component.extensions != null && component.extensions.Length > 0)
                component.extensions.Foreach(item => info.ExtendedProperties.Set(item.name, item.value));

            if (component.properties != null && component.properties.Length > 0)
                component.properties.Foreach(item => RegisterComponentProperty(info, item));

            Kernel.Register(info);
        }

        private void RegisterComponentProperty(ComponentInfo info, property item)
        {
            var prop = info.Implementation.GetProperty(item.name, System.Reflection.BindingFlags.IgnoreCase | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.SetProperty);
            if (prop != null)
            {
                object propValue = null;
                try
                {
                    propValue = Convert.ChangeType(item.value, prop.PropertyType);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }
    }
}
